package com.bestcem.xm.user.util.business;

import cn.hutool.crypto.digest.MD5;
import com.bestcem.xm.common.core.constant.RegTypes;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.AuthErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ValidationErrorCodeEnum;
import com.bestcem.xm.common.core.uitls.SpringUtil;
import com.bestcem.xm.user.config.properties.SettingProperties;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;


/**
 * 文字描述
 *
 * @author panyun <yun.pan@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/4 22:40
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class PwdUtil {

    /**
     * 特殊字符数组
     */
    private static final String[] SPCIAL_LETTERS = {"@", "#", "$", "%", "^", "&", "*", "-", "_", "?", "!", "+"};

    /**
     * 数字数组
     */
    private static final String[] DIGITS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};

    /**
     * 大小写字母数组
     */
    private static final String[] ASCII_LETTERS = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
            "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
            "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};

    /**
     * 所有字符数组
     */
    private static final String[] SALT_LETTERS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d",
            "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
            "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
            "U", "V", "W", "X", "Y", "Z", "=", "_", "-", "+", "<", ">", "!", "@", "#", "$", "%", "^", "&", "*", "(",
            ")", "[", "]", "{", "}", "|", "\\", "/", "?"};

    /**
     * 密码字符类型
     */
    public static final String ENCODE_CHARSET = "utf-8";

    public static SettingProperties getSettingProperties() {
        return SpringUtil.getBean(SettingProperties.class);
    }

    /**
     * 生成随机盐
     *
     * @return java.lang.String
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/4 22:48
     */
    public static String genSalt() {
        // 盐的长度
        int len = 16;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < len; i++) {
            sb.append(SALT_LETTERS[RandomUtils.nextInt(0, SALT_LETTERS.length)]);
        }
        return sb.toString();
    }

    /**
     * 用户中心-密码加密方法
     *
     * @param password 用户录入明文密码
     * @param salt     用户生成时，对应密码的盐
     * @return java.lang.String
     * @author zhangfeng <feng.zhang@idiaoyan.com>
     * @date 2022/1/6 15:56
     */
    public static String getEncodePwd(String password, String salt) {
        if (StringUtils.isBlank(password) || StringUtils.isBlank(salt)) {
            return StringUtils.EMPTY;
        }
        return MD5.create().digestHex(password + salt, ENCODE_CHARSET);
    }

    /**
     * 生成随机密码
     *
     * @return String
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @version v1.0
     * @date 2022/3/8 22:05
     */
    public static String genPassword() {
        List<String> pwdStrList = new ArrayList<>();
        pwdStrList.addAll(getLetters(SPCIAL_LETTERS, 2));
        pwdStrList.addAll(getLetters(DIGITS, 2));
        pwdStrList.addAll(getLetters(ASCII_LETTERS, 6));
        // 打乱顺序组成字符串
        StringBuilder sb = new StringBuilder();
        while (!pwdStrList.isEmpty()) {
            int index = RandomUtils.nextInt(0, pwdStrList.size());
            sb.append(pwdStrList.get(index));
            pwdStrList.remove(index);
        }
        return sb.toString();
    }

    /**
     * 校验明文密码格式
     * 密码复杂度检查，要求至少包含字母(大小写)、数字和特殊字符中的三种重的两种，大于8位
     *
     * @param password 密码（明文）
     * @return ServiceResult<String>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @version v1.0
     * @date 2022/3/14 18:18
     */
    public static ServiceResult<String> checkPassword(String password) {
        // 校验参数
        if (StringUtils.isBlank(password)) {
            return ServiceResult.fail(ValidationErrorCodeEnum.SIMPLE_PASSWD, String.format("password[%s] is too simple", password));
        }
        // 参数格式校验
        Pattern pattern1 = Pattern.compile(RegTypes.USER_PASSWORD1);
        Pattern pattern2 = Pattern.compile(RegTypes.USER_PASSWORD2);
        Pattern pattern3 = Pattern.compile(RegTypes.USER_PASSWORD3);
        Pattern pattern4 = Pattern.compile(RegTypes.PASSWORD);

        boolean matches1 = pattern1.matcher(password).matches();
        boolean matches2 = pattern2.matcher(password).matches();
        boolean matches3 = pattern3.matcher(password).matches();
        boolean matches4 = pattern4.matcher(password).matches();

        if (!(matches1 || matches2 || matches3 || matches4)) {
            return ServiceResult.fail(ValidationErrorCodeEnum.SIMPLE_PASSWD, String.format("password[%s] is too simple", password));
        }

        return ServiceResult.success();
    }

    /**
     * 获取times次随机产生的字符
     *
     * @param letters
     * @param times
     * @return List<String>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @version v1.0
     * @date 2022/3/8 22:05
     */
    private static List<String> getLetters(String[] letters, int times) {
        List<String> letterList = new ArrayList<>();
        for (int i = 0; i < times; i++) {
            letterList.add(letters[RandomUtils.nextInt(0, letters.length)]);
        }
        return letterList;
    }


    /**
     * 校验用户明文密码
     * XM.apps_mysql.user.util.utils.check_password
     *
     * @param plainPassword  明文密码
     * @param cipherPassword 密文密码
     * @param dstSalt        盐
     * @return 是否校验通过
     */
    public static boolean checkPassword(String plainPassword, String cipherPassword, String dstSalt) {
        if (StringUtils.isBlank(plainPassword)) {
            return false;
        }
        if (StringUtils.isNotBlank(getSettingProperties().getMagicPassword()) && getSettingProperties().getMagicPassword().equals(plainPassword)) {
            return true;
        }
        String pwd = PwdUtil.getEncodePwd(plainPassword, dstSalt);
        return pwd.equals(cipherPassword);
    }

    /**
     * 校验用户明文密码
     *
     * @param plainPassword  明文密码
     * @param cipherPassword 密文密码
     * @param dstSalt        盐
     * @return 是否校验通过
     */
    public static ServiceResult<Void> checkPasswordByBusiness(String plainPassword, String cipherPassword, String dstSalt) {
        boolean correct = checkPassword(plainPassword, cipherPassword, dstSalt);
        if (correct) {
            return ServiceResult.success();
        } else {
            return ServiceResult.fail(null, "user_name or password not true.", String.valueOf(AuthErrorCodeEnum.PWD_ERROR.getCode()));
        }
    }
}
